package com.tx.websocket.demo.shiro;

import com.tx.websocket.demo.common.ResourceEnum;
import com.tx.websocket.demo.model.BaseResource;
import com.tx.websocket.demo.model.Role;
import com.tx.websocket.demo.model.User;
import com.tx.websocket.demo.service.ResourceService;
import com.tx.websocket.demo.service.RoleService;
import com.tx.websocket.demo.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

@Component
public class ShiroRealm extends AuthorizingRealm{

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    @Resource
    private ResourceService resourceService;

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //登录用户名
        User user = (User) principalCollection.getPrimaryPrincipal();

        if(user == null)
            throw new AuthorizationException("用户不存在");

        Set<String> roleCodes = new HashSet<>();
        Set<String> permissionMarks = new HashSet<>();

        List<Role> roles = roleService.listRoleByUserId(user.getId());
        List<BaseResource> resources = resourceService.listResByUserId(user.getId());
        //设置角色
        if(!CollectionUtils.isEmpty(roles)) {
            for(Role r : roles) {
                roleCodes.add(r.getCode());
            }
        }

        // 设置权限
        for(BaseResource r : resources) {
            String mark = r.getPermMark();
            if(StringUtils.isNoneBlank(mark)) permissionMarks.add(mark);
        }

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(roleCodes);
        authorizationInfo.setStringPermissions(permissionMarks);
        return authorizationInfo;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String username = (String) authenticationToken.getPrincipal();
        char[] credentials = (char[])authenticationToken.getCredentials();
        String password = new String(credentials);
        User user = userService.getUserByUsername(username);

        if(user == null) throw new UnknownAccountException("用户名或者密码错误");

        if(!user.getEnable()) throw new DisabledAccountException("用户已经失效");

        if(!user.getPassword().equals(password)) throw new AuthenticationException("用户名或者密码错误");

        List<Role> roles = roleService.listRoleByUserId(user.getId());
        List<BaseResource> resources = resourceService.listResByUserId(user.getId());

        //过滤重复角色
        if(CollectionUtils.isNotEmpty(roles))
            user.setRoles(new ArrayList<>(new LinkedHashSet<>(roles)));

        //过滤重复菜单
        if(CollectionUtils.isNotEmpty(resources)) {
            List<BaseResource> baseResources = new ArrayList<>(new LinkedHashSet<>(resources));

            List<BaseResource> topResources = new ArrayList<>();
            Map<Long, List<BaseResource>> topMap = new HashMap<>();
            List<String> permMarks = new ArrayList<>();

            // 模块
            for(BaseResource res : baseResources) {
                if(res.getType().equals(ResourceEnum.MODULE.getValue())) {
                    topResources.add(res);
                    topMap.put(res.getId(), new ArrayList<>());
                }
                permMarks.add(res.getPermMark());
            }

            // 将二级菜单关联到模块下
            for(BaseResource res : baseResources) {
                List<BaseResource> sub = topMap.get(res.getParentId());
                if(sub != null) sub.add(res);
            }

            //设置下级菜单
            for(BaseResource resource : topResources) {
                resource.setSubResources(topMap.get(resource.getId()));
            }

            user.setResources(topResources);
            user.setPermMarks(permMarks);
        }

        return new SimpleAuthenticationInfo(user, credentials, getName());
    }
}
